using System;
using System.Collections.Specialized;
using System.Configuration;
using System.Globalization;
using System.IO;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using WowAceUpdater.Properties;

namespace WowAceUpdater
{
    internal static class Program
    {
        #region Fields

        public const string LOG_FILE_NAME = "waudbg.txt";
        private static StringBuilder _log = new StringBuilder();

        public static bool bAutoExit = false;

        public static bool bDeps = false;

        public static bool bNoPrompts = false;

        public static bool bNoVersionCheck = false;

        public static bool bRefresh = false;

        public static bool bUpdate = false;

        public static CultureInfo ciNeutral = CultureInfo.InvariantCulture;

        public static FileInfo DIAGNOSTIC_LOG = null;

        #endregion

        #region Properties

        internal static StringBuilder Log
        {
            get { return _log; }
            set { _log = value; }
        }

        internal static string TimeStamp
        {
            get { return DateTime.Now.ToString(); }
        }

        #endregion

        #region Internal Methods

        internal static void FlushLog() { FlushLog(false); }
        internal static void FlushLog(bool force)
        {
            
              
            lock (_log)
                try
                {
                    if (force || Settings.Default.DiagnosticLogging)
                    {
                        DIAGNOSTIC_LOG.Refresh();
                        if (DIAGNOSTIC_LOG.Exists && DIAGNOSTIC_LOG.Length > 10000000)
                            File.WriteAllText(DIAGNOSTIC_LOG.FullName, Log.ToString());
                        else
                            File.AppendAllText(DIAGNOSTIC_LOG.FullName, Log.ToString());
                    }
                    Log.Length = 0;
                }
                catch
                {
                }
        }

        internal static void LogErr(string s)
        {
            lock (_log)
            {
                _log.AppendLine(string.Format("[{0}] {1:00} {2}",
                                              TimeStamp,
                                              Thread.CurrentThread.ManagedThreadId,
                                              s));
                
                 FlushLog(true);
            }
        }


        internal static void LogDbg(string s)
        {
            lock (_log)
            {
                _log.AppendLine(string.Format("[{0}] {1:00} {2}",
                                              TimeStamp,
                                              Thread.CurrentThread.ManagedThreadId,
                                              s));
                if (_log.Length > 10000)
                    FlushLog();
            }
        }

        #endregion

        #region Private Methods

        internal static bool IsNetworkAvailable()
        {
            return NetworkInterface.GetIsNetworkAvailable();
        }

        private static void CheckEnvironment()
        {
           // AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

            //if (IsNetworkAvailable())
            //    if (!ApplicationDeployment.IsNetworkDeployed)
            //        if (Settings.Default.UpgradeSettings)
            //        {
            //            Settings.Default.Upgrade();
            //            Settings.Default.UpgradeSettings = false;
            //            Settings.Default.Save();
            //        }

            if (Settings.Default["UpgradeSettings"] != null && Settings.Default.UpgradeSettings)
            {
                Settings.Default.Upgrade();
                Settings.Default.UpgradeSettings = false;
            }

            AssemblyName assLocal = Assembly.GetExecutingAssembly().GetName();
            SettingsPropertyValue lastbuildObj = Settings.Default.PropertyValues["LastBuild"];
            string lastbuild = (lastbuildObj.PropertyValue ?? "0").ToString();
            string currentBuild = assLocal.Version.Revision.ToString();


            if (currentBuild != lastbuild)
            {
                Settings.Default.LastBuild = currentBuild;

                //if (Settings.Default.LastTOCValue == string.Empty)
                //{                
                //    string s = (string)Settings.Default.GetPreviousVersion("LastTOCValue");
                //    if (!string.IsNullOrEmpty(s))
                //    {
                //        LogDbg("Preserving LastTOCValue=" + s);
                //        Settings.Default.LastTOCValue = s;
                //        Settings.Default.Save();
                //    }
                //}



                foreach (SettingsProperty s in Settings.Default.Properties)
                {
                    if (s.Name == "UpgradeSettings" || s.Name == "LastBuild")
                        continue;

                    object o = Settings.Default.GetPreviousVersion(s.Name);

                    try
                    {
                        if (o != null)
                        {
                            if (Settings.Default[s.Name] != null)
                            {
                                LogDbg(string.Format("Migrating - {0} : {1} -> {2}", s.Name,
                                    Settings.Default[s.Name], o));
                                Settings.Default[s.Name] = o;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        LogDbg(e.ToString());
                    }
                }
            } 

            if (Settings.Default["IgnoredAddons"] == null)
            {
                StringCollection i = null;
                try
                {
                    i = (StringCollection)Settings.Default.GetPreviousVersion("IgnoredAddons");
                }
                catch (Exception e)
                {
                    LogDbg(e.ToString());
                }

                if (i == null)
                    i = new StringCollection();

                Settings.Default.IgnoredAddons = i;
            }

            if (Settings.Default["WowInstalls"] == null)
                Settings.Default.WowInstalls = new StringCollection();
            else
            {
                for (int i = 0; i < Settings.Default.WowInstalls.Count; i++ )
                {
                    DirectoryInfo wow = new DirectoryInfo(Settings.Default.WowInstalls[i]);
                    if (Settings.Default.WowInstalls[i] != wow.FullName)
                        Settings.Default.WowInstalls[i] = wow.FullName;
                }
            }
            
            FileSystem.EnsureDirExists(Application.CommonAppDataPath);
            FileSystem.EnsureDirExists(Application.LocalUserAppDataPath);

            DIAGNOSTIC_LOG = new FileInfo(Path.Combine(Application.CommonAppDataPath,
                                                       LOG_FILE_NAME));


            if (String.IsNullOrEmpty(Settings.Default.WowInstallDirectory))
            {
                string s = WowEnvironment.GetInstallFolder();
                if (!string.IsNullOrEmpty(s))
                {
                    DirectoryInfo value = new DirectoryInfo(s);
                    Settings.Default.WowInstallDirectory = value.FullName;

                    if (!Settings.Default.WowInstalls.Contains(value.FullName))
                        Settings.Default.WowInstalls.Add(value.FullName);
                }
            }

            if (string.IsNullOrEmpty(Settings.Default.LastTOCValue) || Settings.Default.LastTOCValue == "20300")
                Settings.Default.LastTOCValue = "20400";

            Settings.Default.Save();

        }

/*
        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {

            Program.LogErr("UNHANDLED EXCEPTION");
            Program.LogErr(e.ExceptionObject.ToString());
        }
*/

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        private static void Main()
        {
#if !DEBUG // try
			try
			{
#endif
            try
            {
                CheckEnvironment();
            }
            catch (Exception ex)
            {
                LogErr("Settings Upgrade Has Failed");
                LogErr(ex.ToString());
            }

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.ThreadException += Application_ThreadException;

            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);


            string[] cmd = Environment.GetCommandLineArgs();

            const string UPDATE = "update";
            const string REFRESH = "refresh";
            const string NOPROMPTS = "noprompts";
            const string AUTOEXIT = "autoexit";
            const string DEPS = "deps";
            const string NOVERCHECK = "nvc";
            const string RESET = "reset";

            foreach (string ss in cmd)
            {
                string s = ss.Substring(1);
                switch (s)
                {
                    case UPDATE:
                        bUpdate = bNoPrompts = true;
                        break;
                    case REFRESH:
                        bRefresh = true;
                        break;
                    case NOPROMPTS:
                        bNoPrompts = true;
                        break;
                    case AUTOEXIT:
                        bAutoExit = true;
                        break;
                    case DEPS:
                        bDeps = true;
                        break;
                    case NOVERCHECK:
                        bNoVersionCheck = true;
                        break;
                    case RESET:
                        Settings.Default.Reset();
                        CheckEnvironment();
                        break;
                }
            }

            LogDbg("");
            LogDbg("-----------------------------------------------------------------------");
            LogDbg("");
            LogDbg(string.Format("   STARTUP: {0} {1} ({2})",
                                 Application.ProductName, Application.ProductVersion,
                                 Assembly.GetExecutingAssembly().GetName().Version.ToString(4)));
            LogDbg("");
            LogDbg("-----------------------------------------------------------------------");
            LogDbg("");
            LogDbg(string.Format("Local settings at {0}", Application.LocalUserAppDataPath));
            LogDbg(string.Format("Roaming settings at {0}", Application.UserAppDataPath));

            Settings.Default.EnableEvents();
            Application.Run(new MainForm());

            FlushLog();

#if !DEBUG // catch (Exception)
			}
			catch (Exception ex)
			{
				MessageBox.Show("An unexpected error occurred. Please make sure you are connected to the internet and restart the application.\n\n" + ex.Message);
				
                LogErr(ex.ToString());
                throw;
			}
#endif
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            if (e.ExceptionObject != null) LogErr(string.Format("Unhandled Exception: Terminating={0}\r\n{1}\r\n{2}", 
                e.IsTerminating, 
                e.ExceptionObject));
        }

        private static void Application_ThreadException(object sender, ThreadExceptionEventArgs ex)
        {
            if (ex.Exception != null) LogErr(string.Format("Unhandled Exception\r\n{0}", ex.Exception));
        }

        #endregion
    }

}